#pragma once

#include "loirey_MyMath.h"
#include "loirey_BasicStructure.h"
#include "loirey_SparseVector.h"

using namespace loirey;

namespace loirey
{

	class CVectorMath
	{
	public:
		static double ManhattanDistance(const CSimpleTypeArray<double>& P, const CSimpleTypeArray<double>& Q);
		static double ManhattanDistance(int Length, const double* P, const double* Q);
		static double EulerDistance(const CSimpleTypeArray<double>& P, const CSimpleTypeArray<double>& Q);
		static double EulerDistance(int Length, const double* P, const double* Q);
		static double CosineSimilarity(const CSimpleTypeArray<double>& P, const CSimpleTypeArray<double>& Q);
		static double CosineSimilarity(int Length, const double* P, const double* Q);
		static double KL_Divergence(const CSimpleTypeArray<double>& P, const CSimpleTypeArray<double>& Q);
		static double KL_Divergence(int Length, const double* P, const double* Q);
	};

	class CComplexNumber
	{
	public:
		double rel, img;

	public:
		inline CComplexNumber() { rel = img = 0.0; }
		inline CComplexNumber(const CComplexNumber& Another) { rel = Another.rel; img = Another.img; }
		inline CComplexNumber(const CComplexNumber* pAnother) { rel = pAnother->rel; img = pAnother->img; }
		inline CComplexNumber(double RealNumber) { rel = RealNumber; img = 0.0; }
		inline CComplexNumber(double RealPart, double ImaginaryPart) { rel = RealPart; img = ImaginaryPart; }
	public:
		inline void SetZero() { rel = img = 0.0; }
		inline void myInit() { rel = img = 0.0; }
		inline void myInit(const CComplexNumber& Another) { rel = Another.rel; img = Another.img; }
		inline void myInit(const CComplexNumber* pAnother) { rel = pAnother->rel; img = pAnother->img; }
		inline void myInit(double RealNumber) { rel = RealNumber; img = 0.0; }
		inline void myInit(double RealPart, double ImaginaryPart) { rel = RealPart; img = ImaginaryPart; }
		inline void Init_by_Polar(double Angle = 0.0, double Length = 1.0)
		{ rel = Length * cos(Angle); img = Length * sin(Angle); }
	public:
		inline CComplexNumber& operator = (const CComplexNumber& Another)
		{ rel = Another.rel; img = Another.img; return *this; }
		inline CComplexNumber& operator = (double RealNumber)
		{ rel = RealNumber; img = 0.0; return *this; }
	public:
		inline bool fIsZero(double eps = EPS) const
		{ return (rel>-eps && rel<+eps && img>-eps && img<+eps); }
		inline double Len2() const { return rel * rel + img * img; }
		inline double Len1() const { return sqrt(rel*rel+img*img); }
	public:
		inline CComplexNumber& operator += (const CComplexNumber& Another)
		{ rel += Another.rel; img += Another.img; return *this; }
		inline CComplexNumber& operator -= (const CComplexNumber& Another)
		{ rel -= Another.rel; img -= Another.img; return *this; }
		inline CComplexNumber& operator *= (const CComplexNumber& Another)
		{
			double tr, ti;
			tr = rel * Another.rel - img * Another.img;
			ti = img * Another.rel + rel * Another.img;
			rel = tr; img = ti;
			return *this;
		}
		inline CComplexNumber& operator /= (const CComplexNumber& Another)
		{
			double tr, ti, tt;
			tt = Another.Len2();
			if (tt < MINIMUM_DOUBLE_EPS_C) return *this;
			tr = rel * Another.rel + img * Another.img;
			ti = img * Another.rel - rel * Another.img;
			rel = tr / tt; img = ti / tt;
			return *this;
		}
	public:
		friend CComplexNumber operator + (const CComplexNumber& A, const CComplexNumber& B);
		friend CComplexNumber operator - (const CComplexNumber& A, const CComplexNumber& B);
		friend CComplexNumber operator * (const CComplexNumber& A, const CComplexNumber& B);
		friend CComplexNumber operator / (const CComplexNumber& A, const CComplexNumber& B);
	};

	CComplexNumber operator + (const CComplexNumber& A, const CComplexNumber& B);
	CComplexNumber operator - (const CComplexNumber& A, const CComplexNumber& B);
	CComplexNumber operator * (const CComplexNumber& A, const CComplexNumber& B);
	CComplexNumber operator / (const CComplexNumber& A, const CComplexNumber& B);
};

